package com.cy.jt.common.redis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;

@EnableCaching //项目初始化时，初始化缓存
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    //RedisTemplate序列化默认使用的是jdkSerializeable,存储二级制字节码
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //1、构建RedisTemplate对象
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //2、设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //3、定义序列化方式(在这里选择jackson)  -- Object.class这个表示可以对任意对象进行序列化
        Jackson2JsonRedisSerializer redisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        //默认这么写 -- 他只是指定了在序列化和反序列化的时候，我们要去查找一些方法时，指定找那些方法
        //PropertyAccessor.ALL -- 表示所有的访问修饰符修饰的方法（public、private、protected）
        //JsonAutoDetect.Visibility.ANY -- ANY表示任意级别访问修饰符修饰的属性
        //设置要序列化的域（通过所有get方法获取所有属性名以及值）
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //可以默认不写
        //启动输入域检查（类不能是final修饰的），并基于json串中的key将其值存储到pojo对象
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);
        redisSerializer.setObjectMapper(objectMapper);
        //4、设置RedisTemplate的序列化
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);
        //spring规范中假如修改bean对象的默认特性，建议调用一下afterPropertiesSet()
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    //如下代码为扩展，假如我们需要自己定义CacheManager，序列化方式，key的有效时长，可以采用这样的方式进行进行设计
    //如下代码可以不写，（不写就用默认的）
    @Bean
    public RedisCacheManager cacheManager(
            RedisConnectionFactory redisConnectionFactory) {
        //初始化一个RedisCacheWriter
        RedisCacheWriter redisCacheWriter =
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //设置CacheManager的值序列化方式为json序列化
        RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
        RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
                        .fromSerializer(jsonSerializer);
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                        .serializeValuesWith(pair);
        //设置默认超过时期是1天
        defaultCacheConfig.entryTtl(Duration.ofDays(1));
        //初始化RedisCacheManager
        return new RedisCacheManager(redisCacheWriter,
                defaultCacheConfig);
    }

}

